package com.m1.tzolkin.model.wheels;

import java.io.Serializable;
import java.util.Map;

import com.m1.tzolkin.model.IAction;
import com.m1.tzolkin.model.ObservableModel;
import com.m1.tzolkin.model.exceptions.NoPlaceException;
import com.m1.tzolkin.model.players.IWorker;


/**
 * Mod�le d'un rouage du jeu.
 * Un rouage est d�fini par une liste d'emplacements o� placer des ouvriers,
 *  une liste d'emplacements bloqu�s, et une s�rie d'actions.
 * A chaque tour de roue, celle-ci d�cale tous ses ouvriers jouables d'un cran, et �jecte ceux
 *  qui doivent �ventuellement l'�tre.
 * Lorsqu'on enl�ve un ouvrier, on propose au joueur un ensemble d'actions � certains co�ts.
 *  
 * @inv <pre>
 *     getMinimumPlace() est la position de la case accessible sur cette roue.
 *     isOccupied(i) ==> il y a un joueur sur la case i </pre>
 *     getName() != null
 *     !getName().trim().equals("")
 *     getBonusLength() >= 0
 *     getCircuitLength() > 0
 *     getFullLength() >= EMPTY_ACTIONS + getCircuitLength() + getBonusLength() > 0
 *     removeWorker() != null </pre>
 * 
 * @cons <pre>
 * $DESC$
 *     Une roue nomm�e s avec n positions.
 *     La liste argument actions contient chaque action possible dans l'ordre.
 *     L'argument bonus indique le nombre de cases � reculade infinie � la fin de la roue. 
 * $ARG$
 *     String s, int n, List<Action> actions, int bonus
 * $PRE$
 *     s != null && !s.trim().equals("");
 *     bonus >= 0
 *     actions != null
 *     n >= actions.size() + bonus + EMPTY_ACTIONS > 0
 * $POST$
 *     Les actions de cette roue sont les actions de la liste.
 *     getFullLength() == n
 *     getCircuitLength() == actions.size()
 *     getBonusLength() == bonus </pre>
 */
public interface IWheel extends ObservableModel, Serializable {
	
	// ATTRIBUTS
	
	// Nombre de cases sans action en d�but de roue
	public static final int EMPTY_ACTIONS = 1;
	
	// REQUETES
	
	/**
	 * Retourne le nom de cette roue.
	 */
	String getName();
	
	/**
	 * Retourne le nombre de cases total de cette roue.
	 */
	int getFullLength();
	
	/**
	 * Retourne le nombre de cases qu'un ouvrier peut parcourir.
	 */
	int getCircuitLength();
	
	/**
	 * Retourne le nombre de cases bonus en fin de roue.
	 */
	int getBonusLength();
	
	/**
	 * Retourne la case minimum o� un ouvrier peut se poser.
	 * L�ve une exception si on ne peut se poser sur aucune case.
	 */
	int getMinimalPosition() throws NoPlaceException;
	
	/**
	 * Retourne le joueur pr�sent en position i.
	 * @pre <pre>
	 *     getCircuitLength() > i >= 0 </pre>
	 */
	IWorker getWorker(int i);
	
	/**
	 * Retourne true si la tour peut supporter i tours
	 *  i.e. si i tours n'�jectent personne.
	 * @pre <pre>
	 *     i > 1 </pre>
	 */
	boolean canMultipleTurn(int i);
	
	/**
	 * Retourne true si les actions de cette roue sont interdites,
	 *  i.e. si elles ne peuvent pas �tre choisies depuis une autre roue
	 *  ou un b�timent sp�cial.
	 */
	boolean isForbidden();
	
	/**
	 * Retourne l'ensemble des actions de cette roue.
	 */
	IAction[] getActions();
	
	// COMMANDES
	
	/**
	 * Place un ouvrier du joueur p sur la roue au plus petit emplacement.
	 * @pre <pre>
	 *     p != null </pre>
	 */
	void placeWorker(IWorker w) throws NoPlaceException;
	
	/**
	 * Bloque l'emplacement i.
	 */
	void block(int i);
	
	/**
	 * Retire l'ouvrier en position i et donne � son joueur toutes les actions possibles.
	 * L'ensemble des actions possibles est calcul� en fonction du ma�s du joueur :
	 *  s'il n'en a pas assez pour reculer suffisamment, l'action n'est pas transmise.
	 * @pre <pre>
	 *     EMPTY_ACTIONS + getCircuitLength() + getBonus() > i >= 0
	 *     occupying(i) != null </pre>
	 * @post <pre>
	 *     occupying(i) == null </pre>
	 */
	Map<IAction, Integer> removeWorker(int i);
	
	/**
	 * Tourne la roue d'un cran.
	 * @post <pre>
	 *     chaque ouvrier avance d'une case.
	 *     isOccupied(EMPTY_ACTIONS + getCircuitLength() + getBonus() - 1)
	 *      ==> l'ouvrier en position EMPTY_ACTIONS + getCircuitLength() + getBonus() - 1 est rendu � son propri�taire. </pre>
	 */
	void turnDay();

}
